package org.amos.server.modules.upms.controller;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.base.Throwables;
import com.wf.captcha.SpecCaptcha;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.amos.core.basic.annotation.Log;
import org.amos.core.basic.base.BaseController;
import org.amos.core.basic.constant.CacheConstant;
import org.amos.core.basic.constant.SystemConstant;
import org.amos.core.basic.enums.LogTypeEnum;
import org.amos.core.basic.exception.ServiceException;
import org.amos.core.basic.vo.R;
import org.amos.core.frame.utils.RedisUtils;
import org.amos.msg.enums.MsgTypeEnum;
import org.amos.msg.model.SmsContentModel;
import org.amos.msg.params.PushMsgParam;
import org.amos.msg.platform.MsgPlatform;
import org.amos.satoken.constants.AuthConstant;
import org.amos.satoken.constants.AuthTypeEnums;
import org.amos.satoken.domain.bo.AuthInfo;
import org.amos.satoken.handler.AmosAuth;
import org.amos.satoken.utils.PwdUtils;
import org.amos.satoken.utils.UserUtils;
import org.amos.server.modules.upms.dto.LoginDTO;
import org.amos.server.modules.upms.dto.LoginMobileDTO;
import org.amos.server.modules.upms.service.IConfigMsgService;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @desc: 用户授权认证相关控制器
 * @author: liubt
 * @date: 2020-12-31
 **/
@Slf4j
@RestController
@RequestMapping("/auth")
@RequiredArgsConstructor
@Api(value = "用户授权认证", tags = "授权接口")
public class AuthController extends BaseController {

    private final RedisUtils redisUtils;
    private final AmosAuth amosAuth;

    private final IConfigMsgService configMsgService;

    @ApiOperation(value = "验证码登录接口")
    @PostMapping(value = "/login/captcha")
    @Log(value = "验证码登录接口", type = LogTypeEnum.LOGIN)
    public R login(@RequestBody @Valid LoginDTO dto) {
        String username = dto.getUsername();
        String password = dto.getPassword();
        String key = dto.getKey();
        String code = dto.getCode();

        //查询验证码
        String captchaCode = (String) redisUtils.get(CacheConstant.CAPTCHA_KEY + key);
        //删除验证码
        redisUtils.del(CacheConstant.CAPTCHA_KEY + key);

        if (StrUtil.isBlank(captchaCode)) {
            throw new ServiceException("验证码已过期");
        }
        if (!code.equalsIgnoreCase(captchaCode)) {
            throw new ServiceException("验证码输入有误");
        }

        // 系统登录认证
        Dict param = Dict.of(
                AuthConstant.USER_NAME, username,
                AuthConstant.PASSWORD, password,
                AuthConstant.AUTH_TYPE, AuthTypeEnums.ACCOUNT.getCode());
        AuthInfo authInfo = amosAuth.login(param);
        return R.ok(authInfo);
    }

    @ApiOperation(value = "验证码登录接口")
    @PostMapping(value = "/login/mobile")
    @Log(value = "手机验证码登录接口", type = LogTypeEnum.LOGIN)
    public R mobileLogin(@RequestBody @Valid LoginMobileDTO dto) {
        String mobilePhone = dto.getMobilePhone();
        String code = dto.getCode();

        //查询验证码
        String captchaCode = (String) redisUtils.get(CacheConstant.MOBILE_CAPTCHA_KEY + mobilePhone);
        //删除验证码
        redisUtils.del(CacheConstant.MOBILE_CAPTCHA_KEY + mobilePhone);
        if (StrUtil.isBlank(captchaCode)) {
            throw new ServiceException("验证码已过期");
        }
        if (!code.equalsIgnoreCase(captchaCode)) {
            throw new ServiceException("验证码输入有误");
        }

        // 系统登录认证
        Dict param = Dict.of(
                AuthConstant.MOBILE, mobilePhone,
                AuthConstant.AUTH_TYPE, AuthTypeEnums.MOBILE.getCode());
        AuthInfo authInfo = amosAuth.login(param);
        return R.ok(authInfo);
    }

    @ApiOperation(value = "二级认证")
    @PostMapping(value = "/openSafe")
    public R openSafe(@RequestParam String token) {
        AuthInfo user = UserUtils.getUser();
        if (Objects.nonNull(user) && PwdUtils.match(token, user.getPassword())) {
            StpUtil.openSafe(SystemConstant.SUB_SAFE_DEFAULT_EXPIRE);
            return R.ok();
        }
        return R.error("认证失败,请重试!");
    }

    @ApiOperation(value = "注销登录")
    @PostMapping(value = "/logout")
    @Log("注销登录")
    public R logout() {
        StpUtil.logout();
        return R.ok();
    }

    @GetMapping("/captcha")
    @ApiOperation(value = "生成图形验证码")
    public R captcha() {
        SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);
        String verCode = specCaptcha.text().toLowerCase();
        String key = UUID.randomUUID().toString();
        // 存入redis并设置过期时间为1分钟
        redisUtils.set(CacheConstant.CAPTCHA_KEY + key, verCode, 1, TimeUnit.MINUTES);
        // 将key和base64返回给前端
        return R.ok(Dict.of("key", key, "img", specCaptcha.toBase64()));
    }

    @ApiOperation(value = "发送手机验证码")
    @GetMapping(value = "/captcha/mobile")
    public R genMobileCaptcha(@RequestParam String mobile) {
        try {
            //查询验证码是否过期，节省短信开支
            String captchaCode = (String) redisUtils.get(CacheConstant.MOBILE_CAPTCHA_KEY + mobile);
            if (StrUtil.isNotBlank(captchaCode)) {
                return R.ok();
            }
            MsgPlatform platform = configMsgService.getDefaultPlatform(MsgTypeEnum.SMS.getType());
            PushMsgParam param = new PushMsgParam();
            SmsContentModel model = new SmsContentModel();

            String code = RandomUtil.randomNumbers(4);
            model.setContent(code);
            model.setType(0);
            param.setReceiver(CollUtil.newHashSet(mobile));
            param.setContentModel(model);
            param.setBusinessId(UUID.randomUUID().toString());
            if (Objects.isNull(platform)) {
                return R.ok();
            }
            Boolean result = platform.push(param);
            if (result) {
                // 存入redis并设置过期时间为1分钟
                redisUtils.set(CacheConstant.MOBILE_CAPTCHA_KEY + mobile, code, 1, TimeUnit.MINUTES);
            }
        }catch (Exception e){
            log.error("[短信验证码]exception:{}", Throwables.getStackTraceAsString(e));
        }finally {
            return R.ok();
        }
    }
}
